package com.cxyjy.cfyuiapi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cxyjy.cfyuiapi.service.PromptWorkflowService;
import com.cxyjy.cfyuiapi.service.QueryHistoryService;
import com.cxyjy.common.util.JObjectUtil;
import com.cxyjy.common.util.JRequestUtil;
import com.cxyjy.common.util.JResponse;
import com.cxyjy.common.util.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.cxyjy.common.constants.CfyuiConstants.*;
import static com.cxyjy.common.util.JObjectUtil.stringValue;
import static com.cxyjy.common.util.ResultCode.CONSTANTS_ERROR;

@Slf4j
@Service("PromptWorkflowService")
public class PromptWorkflowServiceImpl implements PromptWorkflowService {
    @Autowired
    QueryHistoryService queryHistoryService;

    /**
     * 接受前端发送的用户提交图片，提交换脸工作流
     * @param fileName
     * @return
     * @throws IOException
     * @throws IllegalAccessException
     */
    @Override
    public JResponse runReActorFaceSwap(String fileName) throws IOException {
        /**
         * 将comfyUI中换脸插件的工作流json（写死在CfuiConstants.java中的常量PROMPT_DATA）提取成promptMap，
         * 并将换脸模板图片名改为用户上传的图片名（文件已经上传过了，只需要替换文件名）
         *
         * json中的"extra_data" 这个应该包含了comfyui的连线信息，但是comfyui里面的导出API格式json并不包含这个
         * 如果之后要改常量json记得除了生成的client_id和prompt字段以外还有一个"extra_data"
         */
        Map<String, Object> queueMap = JObjectUtil.toMap(JSONObject.parse(VEDIO_FACESWAP_DATA));
        String clientId;
        /**
         * 已将json模板中client_id和换脸模板图片命名为“default”，因为这段代码只需要更改工作流json中这两个字段
         * “client_id”为自动生成的根据UUID16进制数生成的一串10十进制纯数字
         * “image”为用户上传的图片文件名
         */
        if(queueMap.get("client_id").equals("default")){
            //生成一个clientId
            clientId = JObjectUtil.createId();
            queueMap.put("client_id",clientId);
        }else {
            return ResultUtil.error(CONSTANTS_ERROR);
        }
        Map<String,Map<String,Map<String,Object>>> promptMap = (Map)queueMap.get("prompt");
        Map<String, Object> inputsMap = promptMap.get("2").get("inputs");
        if (stringValue(inputsMap.get("image")).equals("default")) {
            inputsMap.replace("image", fileName);
        }else {
            return ResultUtil.error(CONSTANTS_ERROR);
        }
        JSONObject promptResultObj = (JSONObject) (JRequestUtil.sendPostRequest(PROMPT_URL, JSONObject.toJSONString(queueMap)));
        String promptId = stringValue(JObjectUtil.toMap(promptResultObj).get("prompt_id"));
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("clientId",clientId);
        resultMap.put("promptId",promptId);
        log.info("Added a new workflow with promptId:"+promptId);
        return ResultUtil.success(new JSONObject(resultMap));
    }

    @Override
    public JResponse runSingleReActorFaceSwap(String fileName) throws IOException {
        /**
         * 将comfyUI中换脸插件的工作流json提取成promptMap，并将换脸模板图片名改为用户上传的图片名（文件已经上传过了，只需要替换文件名）
         */
        Map<String, Object> queueMap = (Map) JSONObject.parse(SIMPLE_FACESWAP_DATA);
        String clientId;
        //已将json模板中client_id和换脸模板图片命名为“default”，这里给用户随机生成一个client_id并将“default”替换为用户上传的图片文件名
        if(queueMap.get("client_id").equals("default")){
            //生成一个clientId
            clientId = JObjectUtil.createId();
            queueMap.put("client_id",clientId);
        }else {
            return ResultUtil.error(CONSTANTS_ERROR);
        }
        Map<String,Map<String,Map<String,Object>>> promptMap = (Map)queueMap.get("prompt");
        Map<String, Object> inputsMap = promptMap.get("2").get("inputs");
        if (stringValue(inputsMap.get("image")).equals("default")) {
            inputsMap.replace("image", fileName);
        }
        JSONObject promptResultObj = (JSONObject) (JRequestUtil.sendPostRequest(PROMPT_URL, JSONObject.toJSONString(queueMap)));
        String promptId = stringValue(JObjectUtil.toMap(promptResultObj).get("prompt_id"));
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("clientId",clientId);
        resultMap.put("promptId",promptId);
        log.info(stringValue(resultMap));
        return ResultUtil.success(new JSONObject(resultMap));
    }

    @Override
    public JResponse imageReActorFaceSwap(String targetImageName, String sourceImageName) throws IOException{
        JSONObject ifdObject = JSON.parseObject(IMAGE_FACESWAP_DATA);
        JSONObject promptObject = ifdObject.getJSONObject("prompt");
        promptObject.getJSONObject("2").getJSONObject("inputs").put("image",targetImageName);
        promptObject.getJSONObject("124").getJSONObject("inputs").put("image",sourceImageName);
        String clientId = JObjectUtil.createId();
        if(ifdObject.getString("clientId").equals("default")){
            ifdObject.put("clientId",clientId);
        }
        JSONObject promptResultObj = (JSONObject) (JRequestUtil.sendPostRequest(PROMPT_URL, JSONObject.toJSONString(ifdObject)));
        String promptId = promptResultObj.getString("prompt_id");
        log.info("Added a new workflow with promptId:"+promptId);
        JSONObject resultJson = new JSONObject();
        resultJson.put("promptId",promptId);
        resultJson.put("clientId",JObjectUtil.createId());
        return ResultUtil.success(resultJson);
    }

    /**
     * 使用prompt_id调用/history接口查询换脸后生成的视频文件名，并且下载到服务器
     * @param promptId
     * @return
     * @throws IOException
     * @throws IllegalAccessException
     */
    public List<String> returnOutputsVideoByHistory(String promptId) throws IOException, IllegalAccessException {
        Object historyObj = queryHistoryService.queryhistory(promptId);
        Map<String, Object> historyMap = JObjectUtil.toMap(JObjectUtil.toMap(historyObj).get(promptId));
        Map<String, Map<String,Object>> outputsMap = (Map<String, Map<String, Object>>) historyMap.get("outputs");
        /**
         *"outputs":{
         * 	"14": {
         * 		"gifs": [{
         * 			"filename": "Faceswap_1_00010.mp4",
         * 			"subfolder": "",
         * 			"type": "output",
         * 			"format": "video/h264-mp4",
         * 			"frame_rate": 30.0
         *                }] 	},
         * 	"54": {
         * 		"gifs": [{
         * 			"filename": "Faceswap_2_00013.mp4",
         * 			"subfolder": "",
         * 			"type": "output",
         * 			"format": "video/h264-mp4",
         * 			"frame_rate": 30.0
         * 		}]
         * 	},
         * 	"57": {
         * 		"gifs": [{
         * 			"filename": "Faceswap_3_00011.mp4",
         * 			"subfolder": "",
         * 			"type": "output",
         * 			"format": "video/h264-mp4",
         * 			"frame_rate": 30.0
         * 		}]
         * 	},
         * }
         */
        List<String> fileNameList = new ArrayList<>();
        for(Map.Entry entry : outputsMap.entrySet()){
            Map<String, List> valueMap = (Map)entry.getValue();
            Map<String, Object> paramsMap = JObjectUtil.toMap(JSON.parse(stringValue(valueMap.get("gifs").get(0))));
            //获取生成的文件名，不知道“gifs”内的内容为什么是数组形式的
            String fileName = stringValue(JRequestUtil.sendGetRequest(VIEW_URL, paramsMap));
            fileNameList.add(fileName);
        }
        return fileNameList;
    }

}
